package com.burst.reptile.framework.aspectj;

import java.lang.reflect.Method;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;

import com.alibaba.fastjson.JSONObject;
import com.burst.reptile.common.enums.HttpMethod;
import com.burst.reptile.common.utils.ServletUtils;
import com.burst.reptile.common.utils.ToolUtil;
import com.burst.reptile.framework.aspectj.lang.annotation.Msg;
import com.burst.reptile.framework.aspectj.lang.enums.MsgType;
import com.burst.reptile.framework.config.SpringContextHolder;
import com.burst.reptile.framework.manager.AsyncManager;
import com.burst.reptile.framework.manager.factory.AsyncFactory;
import com.burst.reptile.framework.security.LoginUser;
import com.burst.reptile.framework.security.service.TokenService;
import com.burst.reptile.modular.system.entity.SysUser;
import com.burst.reptile.modular.system.service.ISysUserService;
import com.burst.reptile.modular.zp.entity.ZpComment;
import com.burst.reptile.modular.zp.entity.ZpNotice;
import com.burst.reptile.modular.zp.entity.ZpResources;
import com.burst.reptile.modular.zp.service.IZpResourcesService;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 操作日志记录处理
 * 
 * @author wujin
 * @date: 2020年5月27日 下午4:05:08
 */
@Aspect
@Component
@Slf4j
public class MsgAspect {
	

	// 配置织入点
	@Pointcut("@annotation(com.burst.reptile.framework.aspectj.lang.annotation.Msg)")
	public void logPointCut() {
	}

	/**
	 * 处理完请求后执行
	 *
	 * @param joinPoint 切点
	 */
	@AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
	public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
		handleLog(joinPoint, null, jsonResult);
	}

	/**
	 * 拦截异常操作
	 * 
	 * @param joinPoint 切点
	 * @param e         异常
	 */
	@AfterThrowing(value = "logPointCut()", throwing = "e")
	public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
		handleLog(joinPoint, e, null);
	}

	protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult) {
		try {
			// 获得注解
			Msg controllerLog = getAnnotationLog(joinPoint);
			if (controllerLog == null) {
				return;
			}
			
			// 获取当前的用户
			TokenService tokenService = SpringContextHolder.getBean(TokenService.class);
			LoginUser loginUser = tokenService.getWxUser();
			if(ToolUtil.isEmpty(loginUser)) {
				loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
				if(ToolUtil.isEmpty(loginUser)) {
					return;	
				}
			}
			SysUser user = loginUser.getUser();
			if(ToolUtil.isEmpty(user)) {
				return;
			}
			
			// *========数据库日志=========*//
			// 消息类型
			MsgType businessType = controllerLog.businessType();
			String noticeType = businessType.getIndex();
			// 请求参数
			String requestValue = getRequestValue(joinPoint);
			Object data = null;
			if(ToolUtil.isNotEmpty(jsonResult)) {
				JSONObject parseObject = JSONObject.parseObject(JSONObject.toJSONString(jsonResult));
				int code = parseObject.getIntValue("code");
				if(code != 0) {
					return;
				}
				data = parseObject.get("data");
			}
			ZpNotice comment = null;
			if(StrUtil.equals(noticeType, MsgType.COMMENT.getIndex())) { // 评论
				comment = comment(user, requestValue, data);
			}else if(StrUtil.equals(noticeType, MsgType.GIVE.getIndex())) { // 点赞
				comment = give(user, requestValue, data);
			}else if(StrUtil.equals(noticeType, MsgType.COLLECTION.getIndex())) { // 收藏 
				comment = collection(user, requestValue, data);
			}else if(StrUtil.equals(noticeType, MsgType.FANS.getIndex())) { // 粉丝
				comment = fans(user, requestValue, data);
			}else {
				return;
			}
			if(ToolUtil.isNotEmpty(comment)) {
				comment.setNoticeType(noticeType);
				// 保存数据库
				AsyncManager.me().execute(AsyncFactory.recordMsg(comment));
			}
		} catch (Exception exp) {
			// 记录本地异常日志
			log.error("==前置通知异常==");
			log.error("异常信息:{}", exp.getMessage());
			exp.printStackTrace();
		}
	}
	
	/**
	 * 评论
	 * @param m数据封装
	 * @param requestValue 请求参数
	 * @param data 返回参数
	 */
	private ZpNotice comment(SysUser user, String requestValue, Object data) {
		ZpComment comment = JSONObject.parseObject(requestValue, ZpComment.class);
		Long articleId = comment.getArticleId();
		IZpResourcesService resourcesService = SpringContextHolder.getBean(IZpResourcesService.class);
		ZpResources byId = resourcesService.getById(articleId);
		if(ToolUtil.isNotEmpty(byId)) {
			if(!user.getUserId().equals(byId.getUserId())) {
				ZpNotice m = new ZpNotice();
				m.setUserId(user.getUserId());
				m.setArticleId(byId.getArticleId()); // 文章ID
				m.setContent(comment.getContent()); // 评论内容
				m.setContentText(comment.getContent());
				if(ToolUtil.isNotEmpty(data)) {
					long parseLong = NumberUtil.parseLong(data.toString());
					m.setCommentId(parseLong); // 评论所属ID
				}
				m.setRelationUser(byId.getUserId()); // 关联用户
				return m;
			}
		}
		return null;
	}
	
	/**
	 * 点赞
	 * @param m 参数封装
	 * @param requestValue 请求参数
	 * @param data 返回参数
	 */
	private ZpNotice give(SysUser user, String requestValue, Object data) {
		String replace = StrUtil.replace(requestValue, "\"", StrUtil.EMPTY);
		IZpResourcesService resourcesService = SpringContextHolder.getBean(IZpResourcesService.class);
		ZpResources byId = resourcesService.getById(replace);
		if(ToolUtil.isNotEmpty(byId)) {
			if(!user.getUserId().equals(byId.getUserId())) {
				ZpNotice m = new ZpNotice();
				m.setUserId(user.getUserId());
				m.setArticleId(byId.getArticleId()); // 文章ID
				m.setRelationUser(byId.getUserId()); // 关联用户
				return m;
			}
		}
		return null;
	}
	
	/**
	 * 收藏
	 * @param m 参数封装
	 * @param requestValue 请求参数
	 * @param data 返回参数
	 */
	private ZpNotice collection(SysUser user, String requestValue, Object data) {
		String replace = StrUtil.replace(requestValue, "\"", StrUtil.EMPTY);
		IZpResourcesService resourcesService = SpringContextHolder.getBean(IZpResourcesService.class);
		ZpResources byId = resourcesService.getById(replace);
		if(ToolUtil.isNotEmpty(byId)) {
			if(!user.getUserId().equals(byId.getUserId())) {
				ZpNotice m = new ZpNotice();
				m.setUserId(user.getUserId());
				m.setArticleId(byId.getArticleId()); // 文章ID
				m.setRelationUser(byId.getUserId()); // 关联用户
				return m;
			}
		}
		return null;
	}
	
	/**
	 * 关注
	 * @param m 参数封装
	 * @param requestValue 请求参数
	 * @param data 返回参数
	 */
	private ZpNotice fans(SysUser user, String requestValue, Object data) {
		ISysUserService userService = SpringContextHolder.getBean(ISysUserService.class);
		String replace = StrUtil.replace(requestValue, "\"", StrUtil.EMPTY);
		SysUser ruser = userService.getById(replace);
		if(ToolUtil.isNotEmpty(user)) {
			if(!user.getUserId().equals(ruser.getUserId())) {
				ZpNotice m = new ZpNotice();
				m.setUserId(user.getUserId());
				m.setRelationUser(ruser.getUserId()); // 关联用户
				return m;
			}
		}
		return null;
	}


	/**
	 * 获取请求的参数，放到log中
	 * 
	 * @param operLog 操作日志
	 * @throws Exception 异常
	 */
	private String getRequestValue(JoinPoint joinPoint) throws Exception {
		String requestMethod = ServletUtils.getRequest().getMethod();
		if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod)) {
			return argsArrayToString(joinPoint.getArgs());
			
		} else {
			Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest()
					.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
			return paramsMap.toString();
		}
	}

	/**
	 * 是否存在注解，如果存在就获取
	 */
	private Msg getAnnotationLog(JoinPoint joinPoint) throws Exception {
		Signature signature = joinPoint.getSignature();
		MethodSignature methodSignature = (MethodSignature) signature;
		Method method = methodSignature.getMethod();

		if (method != null) {
			return method.getAnnotation(Msg.class);
		}
		return null;
	}

	/**
	 * 参数拼装
	 */
	private String argsArrayToString(Object[] paramsArray) {
		String params = "";
		if (paramsArray != null && paramsArray.length > 0) {
			for (int i = 0; i < paramsArray.length; i++) {
				if (!isFilterObject(paramsArray[i])) {
					try {
						String jsonObj = JSONObject.toJSONString(paramsArray[i]);
						params += jsonObj.toString() + " ";
					} catch (Exception e) {
					}
				}
			}
		}
		return params.trim();
	}

	/**
	 * 判断是否需要过滤的对象。
	 * 
	 * @param o 对象信息。
	 * @return 如果是需要过滤的对象，则返回true；否则返回false。
	 */
	public boolean isFilterObject(final Object o) {
		return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
	}
}
